package com.example.demo.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.example.demo.annotation.AnonymousAccess;
import com.example.demo.config.SecurityProperties;
import com.example.demo.dto.LoginUser;
import com.example.demo.entity.User;
import com.example.demo.security.TokenProvider;
import com.example.demo.security.service.OnlineUserService;
import com.example.demo.security.vo.JwtUser;
import com.example.demo.service.UserService;
import com.example.demo.utils.RedisUtils;
import com.example.demo.utils.ResultUtils;
import com.example.demo.utils.StringUtils;
import com.wf.captcha.ArithmeticCaptcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author zjj
 * @date 2021-04-14
 * 用户登录注册类
 */

//日志注解
@Slf4j
//返回json格式的数据
@RestController
//映射请求
@RequestMapping("/login")
@Api(tags = "系统：用户")
public class LoginController {
    @Value("${rsa.private_key}")
    private String privateKey;

    @Value("${rsa.public_key}")
    private String publicKey;

    @Value("${loginCode.expiration}")
    private Long expiration;

    @Value("${single.login:false}")
    private Boolean singleLogin;

    @Autowired
    private UserService userService;
    @Autowired
    private SecurityProperties properties;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private AuthenticationManagerBuilder authenticationManagerBuilder;
    @Autowired
    private TokenProvider tokenProvider;
    @Autowired
    private OnlineUserService onlineUserService;

    @Autowired
    private PasswordEncoder passwordEncoder;
    /**
     * 注册用户
     * @param user 用户
     * @return 字符串
     */
//    post请求映射
    @PostMapping("/register")
    @ApiOperation("注册用户信息")
    public ResponseEntity<Object> registerUser(@Validated @RequestBody User user) {
        String pwd = user.getPassword();
//        密码加密
//        RSA rsa=new RSA(null,publicKey);
//        String password = rsa.encryptBase64(pwd, KeyType.PublicKey);
        user.setPassword(passwordEncoder.encode(pwd));
//        注册
        userService.create(user);
        return new ResponseEntity<>(ResultUtils.ok("注册用户成功"), HttpStatus.OK);
    }

    /**
     * 登录
     * @param luser 登录用户实体类
     * @return 字符串
     */
    @PostMapping("/login")
    @ApiOperation("用户登录")
    @AnonymousAccess
    public ResponseEntity<Object> login(@RequestBody LoginUser luser, HttpServletRequest request){
        String name=luser.getUserName();
        if(name == null || name == ""){
            return ResponseEntity.ok(ResultUtils.error("用户名错误或者不存在"));
        }
        String psd = luser.getPassword();
        if(psd == null || psd == ""){
            return ResponseEntity.ok(ResultUtils.error("密码错误"));
        }
//        验证码校验
        String uuid = luser.getUuid();
        if(StringUtils.isBlank(uuid)){
            return ResponseEntity.ok(ResultUtils.error("验证码输入不全"));
        }
        String code_redis=(String)redisUtils.get(uuid);
        if(StringUtils.isBlank(code_redis)){
            return ResponseEntity.ok(ResultUtils.error("验证码不存在或已过期"));
        }
        String code = luser.getCode();
        if(StringUtils.isBlank(code) || !code_redis.equalsIgnoreCase(code)){
            return ResponseEntity.ok(ResultUtils.error("验证码错误"));
        }
//        清除验证码
        redisUtils.del(uuid);
        //密码解密
        RSA rsa = new RSA(privateKey,null);
        String passwd=new String(rsa.decrypt(luser.getPassword(),KeyType.PrivateKey));

        UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(luser.getUserName(),passwd);

        Authentication authentication =authenticationManagerBuilder.getObject().authenticate(authenticationToken);

        SecurityContextHolder.getContext().setAuthentication(authentication);
//        生成令牌
        String token = tokenProvider.createToken(authentication);

        final JwtUser jwtUser = (JwtUser)authentication.getPrincipal();
//        保存在线用户信息
        onlineUserService.save(jwtUser,token,request);

//        User us = userService.checkUserInfo(name,psd,privateKey);
        Map<String,Object> maps = new HashMap<>();
        maps.put("user",jwtUser);
        maps.put("token",properties.getTokenStartWith()+token);
//        踢掉之前已经登录的token
        if(singleLogin){
//            踢掉token登录的用户
            onlineUserService.checkLoginOnUser(luser.getUserName(),token);
        }
        return ResponseEntity.ok(ResultUtils.ok("登陆成功").mergeMap(maps));
    }


    /**
     * 生成验证码
     * @return 验证码
     */
    @AnonymousAccess
    @PostMapping(value = "/code")
    @ApiOperation("生成验证码")
    public ResponseEntity<Object> getCode(){
//        算数类型
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(111,36);
//        几位数运算，默认2位数
        captcha.setLen(2);
//        获取运算结果
        String result = captcha.text();
        String uuid = properties.getCodeKey()+ IdUtil.simpleUUID();
//      保存到redis
        redisUtils.set(uuid,result,expiration, TimeUnit.MINUTES);
//        验证码信息
        Map<String,Object> map = new HashMap<String,Object>(2){{
            put("img",captcha.toBase64());
            put("uuid",uuid);
        }};
        return ResponseEntity.ok(ResultUtils.ok("获取验证码成功").mergeMap(map));
    }


}
